home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-29 | 13.7 KB | 399 lines | [TEXT/CWIE] |
- //================================================================================
- // Greg Anderson
- // db+
- //
- // Cursor to an object record
- // 16 May 1994
- // 31 Dec 1994
- //================================================================================
-
- #include "DBElement.h"
-
- #include "DBProperty.h"
- #include "Transaction.h"
-
- #include "DatabaseDocument.h"
- #include "Exceptions.h"
-
- #define INHERITED TDBRecord
-
- //--------------------------------------------------------------------------------
- // TDBElement::~TDBElement
- //--------------------------------------------------------------------------------
- TDBElement::~TDBElement()
- {
- } // TDBElement::~TDBElement
-
- //--------------------------------------------------------------------------------
- // TDBElement::CompareSortKeys
- //--------------------------------------------------------------------------------
- CompareEnumeration TDBElement::CompareSortKeys(TTransaction* t, AConst<TDBRecord> secondObject) const
- {
- CompareEnumeration testResult;
-
- AConst<TDBProperty> nameCursor = this->DBElementRecord()->GetPropertyRecord(t, kNameProperty);
- AConst<TDBProperty> secondName = secondObject->DBElementCursor()->GetPropertyRecord(t, kNameProperty);
- if(nameCursor.Exists() && secondName.Exists())
- {
- testResult = nameCursor->Compare(t, secondName);
- }
- //
- // If either item is empty, then the larger is the one
- // that has data. They are equal if neither has data.
- //
- else
- testResult = (CompareEnumeration)(secondName.Exists() - nameCursor.Exists());
-
- return testResult;
- } // TDBElement::CompareSortKeys
-
- //--------------------------------------------------------------------------------
- // TDBElement::RecordCanHaveElements
- //--------------------------------------------------------------------------------
- Boolean TDBElement::RecordCanHaveElements(TTransaction*) const
- {
- return true;
- } // TDBElement::RecordCanHaveElements
-
- //--------------------------------------------------------------------------------
- // TDBElement::RecordCanHaveProperties
- //--------------------------------------------------------------------------------
- Boolean TDBElement::RecordCanHaveProperties(TTransaction*) const
- {
- return true;
- } // TDBElement::RecordCanHaveProperties
-
- //--------------------------------------------------------------------------------
- // TDBElement::GetPropertyRecord
- //--------------------------------------------------------------------------------
- AConst<TDBProperty> TDBElement::GetPropertyRecord(TTransaction* t, long propertyID) const
- {
- TDataRecordComparisonObject searchObject(propertyID);
- AConst<TDBProperty> theProperty;
-
- AConst<TDBProperty> topProperty = this->Properties(t);
- if(topProperty.Exists())
- {
- //
- // We call 'FindItemInSubTree' instead of 'FindItemInTree' because
- // we know we're already at the top of the property tree
- //
- AConst<TDBRecord> tempProperty = topProperty->FindItemInSubTree(t, &searchObject);
- if(tempProperty.Exists())
- theProperty = tempProperty->DBPropertyCursor();
- }
-
- return theProperty;
- } // TDBElement::GetPropertyRecord
-
- //--------------------------------------------------------------------------------
- // TDBElement::GetNamedElement
- //--------------------------------------------------------------------------------
- AConst<TDBElement> TDBElement::GetNamedElement(TTransaction* t, const TAbstractDataReference& nameSpec) const
- {
- TObjectRecordComparisonObject searchObject(nameSpec);
- AConst<TDBElement> theElement;
-
- AConst<TDBElement> topElement = this->Elements(t);
- if(topElement.Exists())
- {
- //
- // We call 'FindItemInSubTree' instead of 'FindItemInTree' because
- // we know we're already at the top of the element tree
- //
- AConst<TDBRecord> tempElement = topElement->FindItemInSubTree(t, &searchObject);
- if(tempElement.Exists())
- theElement = tempElement->DBElementCursor();
- }
-
- return theElement;
- } // TDBElement::GetNamedElement
-
- //--------------------------------------------------------------------------------
- // TDBElement::GetLongwordProperty
- //--------------------------------------------------------------------------------
- long TDBElement::GetLongwordProperty(TTransaction* t, long propertyID) const
- {
- AConst<TDBProperty> dataCursor = this->GetPropertyRecord(t, propertyID);
- long result = 0;
- if(dataCursor.Exists())
- {
- result = dataCursor->GetLongData(t);
- }
- // ••• fail if does not exist
- return result;
- } // TDBElement::GetLongwordProperty
-
- //--------------------------------------------------------------------------------
- // TDBElement::GetTypedProperty
- //--------------------------------------------------------------------------------
- void TDBElement::GetTypedProperty(TTransaction* t, long propertyID, TUpdataDataReference& data) const
- {
- AConst<TDBProperty> dataCursor = this->GetPropertyRecord(t, propertyID);
- if(dataCursor.Exists())
- {
- dataCursor->GetTypedData(t, data);
- }
- // ••• fail if does not exist
- } // TDBElement::GetTypedProperty
-
- //--------------------------------------------------------------------------------
- // TDBElement::Verify
- //--------------------------------------------------------------------------------
- void TDBElement::Verify(TTransaction* t, Boolean verifyDeep /* = false */) const
- {
- //
- // Check properties and elements
- //
- AConst<TDBElement> elements = this->Elements(t);
- if(elements.Exists())
- {
- if(elements->LiteralParentSibling(t)->RecordIndex() != this->RecordIndex())
- DebugStr("\pTDBElement::Verify top element doesn't point back");
- }
- AConst<TDBProperty> properties = this->Properties(t);
- if(properties.Exists())
- {
- if(properties->LiteralParentSibling(t)->RecordIndex() != this->RecordIndex())
- DebugStr("\pTDBElement::Verify top property doesn't point back");
- }
-
- INHERITED::Verify(t, verifyDeep);
-
- if(verifyDeep)
- {
- if(elements.Exists())
- elements->Verify(t, true);
- if(properties.Exists())
- properties->Verify(t, true);
- }
- } // TDBElement::Verify
-
- //--------------------------------------------------------------------------------
- // TDBElement::InitializeNewRecord
- //--------------------------------------------------------------------------------
- void TDBElement::InitializeNewRecord(TTransaction* t)
- {
- INHERITED::InitializeNewRecord(t);
-
- this->SetRecordFlags(t, kInitialObjectRecordFlags);
- this->SetParentElementIndex(t, kNilIndex);
- this->SetTopChildIndex(t, kNilIndex);
- this->SetTopPropertyIndex(t, kNilIndex);
- this->SetNamePropertyIndex(t, kNilIndex);
- } // TDBElement::InitializeNewRecord
-
- //--------------------------------------------------------------------------------
- // TDBElement::PropertyValueChanged
- //
- // Whenever a property changes value, it informs the record that owns it by
- // calling this method.
- //--------------------------------------------------------------------------------
- void TDBElement::PropertyValueChanged(TTransaction* t, AConst<TDBProperty> propertyThatChanged)
- {
- //
- // If our name changes, then resort this record within the tree it's stored in.
- // Note that we will also get notification when our name is removed from the
- // tree, so we need to check for that case as well.
- //
- if((propertyThatChanged->PropertyID(t) == kNameProperty) && (propertyThatChanged->RecordIsInATree(t)))
- {
- this->SetNamePropertyIndex(t, propertyThatChanged->RecordIndex());
- this->ResortThisRecord(t);
- }
- //
- // If the property that changed was our cached name property,
- // but its property ID is no longer kNameProperty or it is no
- // longer in our property tree, then clear our name property
- // cache entry.
- //
- else if(propertyThatChanged->RecordIndex() == this->NamePropertyIndex(t))
- {
- this->SetNamePropertyIndex(t, kNilIndex);
- this->ResortThisRecord(t);
- }
- } // TDBElement::PropertyValueChanged
-
- //--------------------------------------------------------------------------------
- // TDBElement::GetPropertyRecordForceCreate
- //--------------------------------------------------------------------------------
- AConst<TDBProperty> TDBElement::GetPropertyRecordForceCreate(TTransaction* t, long propertyID)
- {
- AConst<TDBProperty> theProperty = GetPropertyRecord(t, propertyID);
-
- //
- // If 'forceCreate' is true and we could not find the property, then
- // create it now and add it to the tree
- //
- if(theProperty.Exists() == false)
- {
- AnUpdate<TDBProperty> updateProperty = this->DBDocument()->NewDBProperty(t);
- updateProperty->SetPropertyID(t, propertyID);
- this->AddProperty(t, updateProperty);
-
- theProperty = AConst<TDBProperty>(updateProperty);
-
- //
- // Cache the index of the name when it's created
- //
- if(propertyID == kNameProperty)
- {
- this->SetNamePropertyIndex(t, theProperty->RecordIndex());
- }
- }
-
- return theProperty;
- } // TDBElement::GetPropertyRecordForceCreate
-
- //--------------------------------------------------------------------------------
- // TDBElement::AddElement
- //--------------------------------------------------------------------------------
- void TDBElement::AddElement(TTransaction* t, AnUpdate<TDBElement> newElement)
- {
- AConst<TDBElement> topElement = this->Elements(t);
- if(topElement.Exists())
- {
- (this->Transaction()->GetDBElementUpdatePointer(topElement))->Insert(t, newElement);
- }
- else
- {
- this->SetElements(t, newElement);
- newElement->SetRecordIsAtTopOfTree(t, true);
- newElement->SetParentSibling(t, this);
- }
-
- //
- // One of these days we should number the tree
- //
- newElement->SetNodeNumber(t, 0);
- newElement->SetParentElement(t, this);
-
- #ifdef SLOWDEBUG
- newElement->Verify(t);
- this->Verify(t, true);
- #endif
- } // TDBElement::AddElement
-
- //--------------------------------------------------------------------------------
- // TDBElement::AddProperty
- //--------------------------------------------------------------------------------
- void TDBElement::AddProperty(TTransaction* t, AnUpdate<TDBProperty> newProperty)
- {
- //
- // Check to see if there's already a property with this ID
- //
- AConst<TDBProperty> existingProperty = this->GetPropertyRecord(t, newProperty->PropertyID(t));
- Boolean addNewPropertyToTree = true;
-
- if(existingProperty.Exists())
- {
- //
- // If the new property is already in the tree, then we
- // don't really need to do anything else.
- //
- if(existingProperty->RecordIndex() == newProperty->RecordIndex())
- {
- addNewPropertyToTree = false;
- }
- //
- // Delete the existing property if it isn't the same property
- // that's already in the tree.
- //
- // NOTE: It would be WAY better to copy the contents of
- // "newProperty" into "existingProperty" and then free the
- // new property; that way, properties that have been placed
- // close to the record they are in will remain in their optimal
- // position. The problem with that technique is that it
- // would require clients of "AddProperty" to take into account
- // that "newProperty" might be deleted.
- //
- else
- {
- AnUpdate<TDBProperty> updateExistingProperty = this->Transaction()->GetDBPropertyUpdatePointer(existingProperty);
- updateExistingProperty->RemoveFromTree(t);
- updateExistingProperty->FreeThisRecord(t);
- }
- }
-
- //
- // Add the new property to the tree after the old one's gone
- //
- if(addNewPropertyToTree == true)
- {
- AConst<TDBProperty> topProperty = this->Properties(t);
- if(topProperty.Exists())
- {
- (this->Transaction()->GetDBPropertyUpdatePointer(topProperty))->Insert(t, newProperty);
- }
- else
- {
- this->SetProperties(t, newProperty);
- newProperty->SetRecordIsAtTopOfTree(t, true);
- newProperty->SetParentSibling(t, this);
- }
- }
-
- //
- // Write in the index of this property if it's the "name" property
- //
- if(newProperty->PropertyID(t) == kNameProperty)
- {
- this->SetNamePropertyIndex(t, newProperty->RecordIndex());
- }
-
- #ifdef SLOWDEBUG
- newProperty->Verify(t);
- this->Verify(t, true);
- #endif
- } // TDBElement::AddProperty
-
- //--------------------------------------------------------------------------------
- // TDBElement::AddLongwordProperty
- //--------------------------------------------------------------------------------
- void TDBElement::AddLongwordProperty(TTransaction* t, long propertyID, long newValue)
- {
- AConst<TDBProperty> dataCursor = this->GetPropertyRecordForceCreate(t, propertyID);
- (this->Transaction()->GetDBPropertyUpdatePointer(dataCursor))->SetLongData(t, newValue);
- } // TDBElement::AddLongwordProperty
-
- //--------------------------------------------------------------------------------
- // TDBElement::AddTypedProperty
- //--------------------------------------------------------------------------------
- void TDBElement::AddTypedProperty(TTransaction* t, long propertyID, const TAbstractDataReference& data)
- {
- AConst<TDBProperty> dataCursor = this->GetPropertyRecordForceCreate(t, propertyID);
- (this->Transaction()->GetDBPropertyUpdatePointer(dataCursor))->SetTypedData(t, data);
- } // TDBElement::AddTypedProperty
-
- //--------------------------------------------------------------------------------
- // TObjectRecordComparisonObject::TestObject
- //--------------------------------------------------------------------------------
- CompareEnumeration TObjectRecordComparisonObject::TestObject(TTransaction* t, AConst<TDBRecord> testObject)
- {
- CompareEnumeration testResult;
-
- AConst<TDBProperty> nameCursor = testObject->DBElementCursor()->GetPropertyRecord(t, kNameProperty);
- if(nameCursor.Exists())
- {
- //
- // The relationship we want to test for is search key with the name cursor,
- // but we must do the test in the reverse order (name cursor with search key)
- // because the data reference for the name cursor is unavailable to us (private).
- // Therefore, we do the test we can and then negate it.
- //
- testResult = (CompareEnumeration)(-((int)nameCursor->Compare(t, fSearchKey)));
- }
- //
- // If the name of the item is empty, then it is equal
- // to the search key if the search key is empty, and
- // it is less than the search key if the search key has
- // any data.
- //
- else
- testResult = fSearchKey.DataLength() == 0 ? kObjectKeysEqual : kSecondObjectComesBefore;
- // testResult = fSearchKey.Compare(TConstDataReference('TEXT', 0, (Ptr)&fSearchKey));
-
- return testResult;
- } // TObjectRecordComparisonObject::TestObject
-
-